<?php

namespace july\julyadmin\builder\traits\actions;

use july\julyadmin\builder\Form;
use july\julyadmin\builder\table\DataTable;
use july\julyadmin\common\logic\ExportLogic;

/**
 * 导出
 */
trait HasExport
{
    /**
     * 导出时在这里面的是允许的，其余都不允许
     */
    protected $exportOnly = [];

    /**
     * 导出时在这里面的是不允许的，其余都允许
     */
    protected $exportExcept = [];

    //每次导出几条
    protected $export_limit = 500;

    /**
     * 导出
     * @Author   july
     * @DateTime 2023-09-04
     * @param    string     $page             第几页
     * @param    string     $type             类型：excel,csv
     * @param    string     $sort             排序:id desc
     * @param    array      $search           搜索条件
     * @param    array      $no_select_fields 不导出字段
     */
    public function export($page = 1, $type = 'excel', $sort = '', $search = [], $no_select_fields = [])
    {
        ini_set('max_execution_time', 0);
        if ($sort) {
            $this->sort = $sort;
        }

        //如果没有选中的字段不为空，将允许导出字段从列表中删除
        if ($no_select_fields && $this->exportOnly && !$this->exportExcept) {
            foreach ($no_select_fields as $nsk => $nsv) {
                $key = array_search($nsv, $this->exportOnly);
                if (isset($key)) {
                    unset($this->exportOnly[$key]);
                }
            }
        }

        //如果没有选中的字段不为空，把没有选中的字段放入不允许导出的字段列表
        if ($no_select_fields && !$this->exportOnly) {
            $this->exportExcept = array_unique(array_merge($this->exportExcept, $no_select_fields));
        }

        // //如果有连表操作，并且dataModel有实例化对象，那么判断一下排序条件有没有带表名，没有就处理一下加上
        if ($this->relationWithJoins && $this->dataModel) {
            $sorts = array_filter(explode(',', $this->sort));
            array_walk($sorts, function (&$sort_value, $key) {
                if (stripos($sort_value, '.') === false) {
                    $class      = class_basename($this->dataModel);
                    $class      = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $class));
                    $sort_value = $class . '.' . $sort_value;
                }
            });
            $this->sort = implode(',', $sorts);
        }

        $this->table = new DataTable($this);
        //设置分组字段
        $this->table->treeTableGroupField($this->treeTableGroupField);
        //设置表格id
        $this->table->tableType($this->tableType)->tableId(request()->controller() . request()->action() . "_table");
        //渲染页面
        $this->buildPage($this->table);
        //处理导出数据
        $where = $this->filterWhere($search);
        $data  = $this->buildDataList($where, $this->export_limit, $this->sort, $page, $this->total);
        if (isset($data['data'])) {
            $data['data'] = $this->handleToValue($this->table->form->parent->table->form->to, $data['data']);
        }

        //如果是树形表格，处理一下，递归获取下级信息
        $newList = [];
        if ($this->tableType == 'treeTable') {
            foreach ($data['data'] as $data_k => $data_v) {
                $newList[] = $data_v;
                $childrens = [];
                $this->getExportChildrens($data_v, $childrens, "├─\t");
                if ($childrens) {
                    foreach ($childrens as $children_k => $children) {
                        $newList[] = $children;
                    }
                }
            }
        } else {
            $newList = $data['data'];
        }
        $list = [];
        foreach ($newList as $data_k => $data_v) {
            $row = [];
            foreach ($this->table->form->cols[0] as $tfk => $tfv) {
                if (isset($tfv->field) && $tfv->field) {
                    //如果字段不允许导出，跳过
                    if ($this->exportExcept && !$this->exportOnly) {
                        if (in_array($tfv->field, $this->exportExcept)) {
                            continue;
                        }
                    }

                    //如果字段不在允许导出列表，跳过
                    if (!$this->exportExcept && $this->exportOnly) {
                        if (!in_array($tfv->field, $this->exportOnly)) {
                            continue;
                        }
                    }

                    $field = array_filter(explode('.', $tfv->field));
                    if (count($field) == 1) {
                        $row[$tfv->field] = isset($data_v[$tfv->field]) ? $data_v[$tfv->field] : '';
                    } else {
                        $val = $data_v;
                        foreach ($field as $field_name) {
                            if (isset($val[$field_name])) {
                                $val = $val[$field_name];
                            }
                        }
                        $row[$tfv->field] = $val;
                    }

                    //根据类型处理内容
                    //处理数字
                    if (is_numeric($row[$tfv->field]) && !strstr($row[$tfv->field], '.')) {
                        $row[$tfv->field] .= "\t";
                    }

                    //处理按钮
                    if ($tfv->form_type == 'switchBtn') {
                        $row[$tfv->field] = trim($row[$tfv->field]);
                        if (is_numeric($row[$tfv->field])) {
                            $row[$tfv->field] = $row[$tfv->field] ? $tfv->switchBtnText[0] : $tfv->switchBtnText[1];
                        }
                    }
                }
            }
            $list[] = $row;
        }

        //获取headers
        $headers = [];
        foreach ($this->table->form->cols[0] as $tfk => $tfv) {
            if (isset($tfv->title) && isset($tfv->field)) {
                //如果字段不允许导出，跳过
                if ($this->exportExcept && !$this->exportOnly) {
                    if (in_array($tfv->field, $this->exportExcept)) {
                        continue;
                    }
                }

                //如果字段不在允许导出列表，跳过
                if (!$this->exportExcept && $this->exportOnly) {
                    if (!in_array($tfv->field, $this->exportOnly)) {
                        continue;
                    }
                }
                $headers[] = $tfv->title;
            }
        }

        //写入文件
        $title       = $this->pageTitle . session('admininfo.id');
        $exportLogic = new ExportLogic($title, $headers, []);
        if ($page == 1) {
            if ($type == 'excel') {
                if ($exportLogic->excelExists($title)) {
                    $exportLogic->excelDelete($title);
                }
            } else {
                if ($exportLogic->csvExists($title)) {
                    $exportLogic->csvDelete($title);
                }
            }
        }

        $exportLogic->appendData($list);
        if ($type == 'excel') {
            $result = $exportLogic->exportExcel();
        } else {
            $result = $exportLogic->exportCsv();
        }

        $result['data']['page']     = $page;
        $result['data']['total']    = $data['count'];
        $result['data']['pages']    = ceil($data['count'] / $this->export_limit);
        $result['data']['progress'] = min(100, ceil($page / $result['data']['pages'] * 100));
        return json($result);
    }

    /**
     * 获取需要导出的数据的所有下级列表
     * @Author   july
     * @DateTime 2023-09-06
     * @param    array     $data      需要导出的当前行
     * @param    array     $childrens 下级数据列表
     * @param    string    $prefix    前缀，为了让下级数据层级更明显，可以添加前缀，比如一个减号-，那么就会在每个下级的前面叠加显示
     */
    public function getExportChildrens($data = [], &$childrens = [], $prefix = '', $newPrefix = '')
    {
        if (isset($data['children']) && $data['children']) {
            $newPrefix .= $prefix;
            foreach ($data['children'] as $data_k => $data_v) {
                $data_v[$this->treeTableGroupField] = $newPrefix . $data_v[$this->treeTableGroupField];
                $childrens[]                        = $data_v;

                $this->getExportChildrens($data_v, $childrens, $prefix, $newPrefix);
            }
        }
    }
}
